<template>
  <div class="containers">
    <el-container style="align-items: stretch">
      <el-main class="flow-viewer">
        <div class="process-status">
          <span class="intro">状态：</span>
          <div class="finish">已办理</div>
          <div class="processing">办理中</div>
          <div class="todo">未进行</div>
        </div>
        <!-- 流程图显示 -->
        <div v-loading="loading" class="canvas" ref="flowCanvas"></div>
        <!--  按钮区域  -->
        <el-button-group class="button-group">
          <el-tooltip effect="dark" content="适中" placement="bottom">
            <el-button size="small" icon="el-icon-rank" @click="fitViewport"/>
          </el-tooltip>
          <el-tooltip effect="dark" content="放大" placement="bottom">
            <el-button size="small" icon="el-icon-zoom-in" @click="zoomViewport(true)"/>
          </el-tooltip>
          <el-tooltip effect="dark" content="缩小" placement="bottom">
            <el-button size="small" icon="el-icon-zoom-out" @click="zoomViewport(false)"/>
          </el-tooltip>
        </el-button-group>
      </el-main>
    </el-container>
  </div>
</template>

<script>
import {flowTaskInfo} from "@/api/flowable/process";
import ZoomScrollModule from "diagram-js/lib/navigation/zoomscroll";
import MoveCanvasModule from "diagram-js/lib/navigation/movecanvas";
import GridModule from 'diagram-js-grid';
import BpmnViewer from "bpmn-js/lib/Viewer";

export default {
  name: "BackViewer",
  /** 组件传值  */
  props: {
    // 回显数据传值
    flowData: {
      type: Object,
      default: () => {
      },
      required: false
    },
  },
  data() {
    return {
      bpmnViewer: null,
      flowDetail: {},
      loading: true,
    }
  },
  /** 传值监听 */
  watch: {
    flowData: {
      handler(newValue) {
        if (Object.keys(newValue).length > 0) {
          // 生成实例
          this.bpmnViewer && this.bpmnViewer.destroy();
          this.bpmnViewer = new BpmnViewer({
            container: this.$refs.flowCanvas,
            height: 'calc(100vh - 200px)',
            additionalModules: [
              ZoomScrollModule,
              MoveCanvasModule,
              GridModule
            ],
          })
          this.loadFlowCanvas(newValue);
          // 节点注册点击事件
          this.initNodeClick(this.bpmnViewer,newValue);
        }
      },
      immediate: true
    },
  },
  created() {

  },
  methods: {
    //节点注册点击事件
    initNodeClick(bpmnViewer, flowData) {
      const eventBus = bpmnViewer.get('eventBus');
      const canvas = bpmnViewer.get('canvas');
      eventBus.on('element.click', (e) => {
        if (e.element.type === "bpmn:UserTask") {
          // 查找当前节点
          const userTask = flowData.nodeData.find(node => node.key === e.element.id)
          const name = e.element.businessObject?.name ?? "";
          if (userTask && userTask.completed) {
            this.$emit('handleReturnTaskSelect',{key: e.element.id, name});
          } else {
            this.$modal.msgError(name + "节点未办理, 请重新选择");
          }
        }
      });
      eventBus.on('element.hover', (e) => {
        if (e.element.type === "bpmn:UserTask") {
          canvas.addMarker(e.element.id, 'highlight-hover')
        }
      });
      eventBus.on('element.out', (e) => {
        if (e.element.type === "bpmn:UserTask") {
          canvas.removeMarker(e.element.id, 'highlight-hover')
        }
      });
    },

    // 加载流程图片
    async loadFlowCanvas(flowData) {
      try {
        await this.bpmnViewer.importXML(flowData.xmlData);
        await this.fitViewport();
        // 流程线高亮设置
        if (flowData.nodeData !== undefined && flowData.nodeData.length > 0) {
          await this.fillColor(flowData.nodeData);
        }
      } catch (err) {
        console.error(err.message, err.warnings)
      }
    },

    // 让图能自适应屏幕
    fitViewport() {
      this.zoom = this.bpmnViewer.get('canvas').zoom("fit-viewport", "auto");
      this.loading = false;
    },

    // 放大缩小
    zoomViewport(zoomIn = true) {
      this.zoom = this.bpmnViewer.get('canvas').zoom()
      this.zoom += (zoomIn ? 0.1 : -0.1)
      if (this.zoom >= 0.2) this.bpmnViewer.get('canvas').zoom(this.zoom);
    },

    // 设置高亮颜色的
    fillColor(nodeData) {
      const canvas = this.bpmnViewer.get('canvas');
      const definitions = this.bpmnViewer.getDefinitions();

      // 遍历流程定义的根元素中的每个节点
      definitions.rootElements[0].flowElements.forEach(node => {
        const completeTask = nodeData.find(task => task.key === node.id);
        const todoTask = nodeData.find(task => !task.completed);

        // 判断节点类型
        const isTaskOrGateway = node.$type.indexOf('Task') !== -1 || node.$type.indexOf('Gateway') !== -1;
        const isStartEvent = node.$type === 'bpmn:StartEvent';
        const isEndEvent = node.$type === 'bpmn:EndEvent';
        const isEventNode = node.$type === 'bpmn:IntermediateCatchEvent' || node.$type === 'bpmn:IntermediateThrowEvent' || node.$type === 'bpmn:BoundaryEvent';

        if (isTaskOrGateway) {
          // 用户任务节点或网关节点处理
          this.handleTaskOrGateway(node, canvas, nodeData, completeTask, todoTask);
        } else if (isStartEvent) {
          // 开始事件节点处理
          this.handleStartEvent(node, canvas, nodeData);
        } else if (isEndEvent) {
          // 结束事件节点处理
          this.handleEndEvent(node, canvas, nodeData);
        } else if (isEventNode) {
          // 事件节点处理
          this.handleEventNode(node, canvas, nodeData, completeTask);
        } else if (node.$type === 'bpmn:SubProcess') {
          if (completeTask) {
            if (todoTask && completeTask.key === todoTask.key && !todoTask.completed) {
              canvas.addMarker(node.id, todoTask.completed ? 'highlight' : 'highlight-todo');
            } else {
              canvas.addMarker(node.id, completeTask.completed ? 'highlight' : 'highlight-todo');
            }
          }
          // 子任务处理
          this.handleSubProcess(node, canvas, nodeData);

          // 子任务的出线处理
          node.outgoing?.forEach(flow => {
            const targetTask = nodeData.find(task => task.key === flow.targetRef.id);
            if (targetTask) {
              if (flow.$type === 'bpmn:SequenceFlow') {
                // 顺序流程线处理
                const sequenceFlow = nodeData.find(task => task.key === flow.id);
                if (sequenceFlow && sequenceFlow.completed) {
                  canvas.addMarker(flow.id, 'highlight');
                }
              } else {
                // 其他类型的流程线处理
                canvas.addMarker(flow.id, targetTask.completed ? 'highlight' : 'highlight-todo');
                canvas.addMarker(flow.targetRef.id, targetTask.completed ? 'highlight' : 'highlight-todo');
              }
            }
          })
        }
      });
    },

    // 用户任务节点或网关节点处理
    handleTaskOrGateway(node, canvas, nodeData, completeTask, todoTask) {
      if (completeTask) {
        const highlightType = completeTask.completed ? 'highlight' : 'highlight-todo';
        canvas.addMarker(node.id, highlightType);

        // 遍历当前节点的出线
        node.outgoing?.forEach(flow => {
          const targetTask = nodeData.find(task => task.key === flow.targetRef.id);

          if (targetTask) {
            if (todoTask && completeTask.key === todoTask.key && !todoTask.completed) {
              // 待办任务标记为高亮或待办
              canvas.addMarker(flow.id, todoTask.completed ? 'highlight' : 'highlight-todo');
              canvas.addMarker(flow.targetRef.id, todoTask.completed ? 'highlight' : 'highlight-todo');
            } else {
              if (flow.$type === 'bpmn:SequenceFlow') {
                // 顺序流程线处理
                const sequenceFlow = nodeData.find(task => task.key === flow.id);
                if (sequenceFlow && sequenceFlow.completed) {
                  canvas.addMarker(flow.id, 'highlight');
                }
              } else {
                // 其他类型的流程线处理
                canvas.addMarker(flow.id, targetTask.completed ? 'highlight' : 'highlight-todo');
                canvas.addMarker(flow.targetRef.id, targetTask.completed ? 'highlight' : 'highlight-todo');
              }
            }
          }
        });
      }
    },

    // 开始事件节点处理
    handleStartEvent(node, canvas, nodeData) {
      // 遍历当前节点的出线
      node.outgoing.forEach(flow => {
        const completeTask = nodeData.find(task => task.key === flow.targetRef.id);
        if (completeTask) {
          // 标记当前节点和流程线为高亮
          canvas.addMarker(node.id, 'highlight-event');
          canvas.addMarker(flow.id, 'highlight');
        }
      });
    },

    // 结束事件节点处理
    handleEndEvent(node, canvas, nodeData) {
      // 如果最后一个任务与当前节点相同且已完成，则将当前节点标记为高亮
      const endTask = nodeData.find(task => task.key === node.id);
      if (endTask && endTask.completed) {
        canvas.addMarker(node.id, 'highlight');
      }
    },

    // 事件节点处理
    handleEventNode(node, canvas, nodeData, completeTask) {
      const marker = completeTask ? (completeTask.completed ? 'highlight-event' : 'highlight-event-todo') : '';
      canvas.addMarker(node.id, marker);

      // 遍历当前节点的出线
      node.outgoing?.forEach(flow => {
        if (flow.$type === 'bpmn:SequenceFlow') {
          // 顺序流程线处理
          const sequenceFlow = nodeData.find(task => task.key === flow.id);
          if (sequenceFlow && sequenceFlow.completed) {
            canvas.addMarker(flow.id, 'highlight');
          }
        }
      });
    },

    // 子任务处理
    handleSubProcess(subProcess, canvas, nodeData) {
      subProcess.flowElements.forEach(node => {
        const completeTask = nodeData.find(task => task.key === node.id);
        const todoTask = nodeData.find(task => !task.completed);

        // 判断节点类型
        const isTaskOrGateway = node.$type.indexOf('Task') !== -1 || node.$type.indexOf('Gateway') !== -1;
        const isStartEvent = node.$type === 'bpmn:StartEvent';
        const isEndEvent = node.$type === 'bpmn:EndEvent';
        const isEventNode = node.$type === 'bpmn:IntermediateCatchEvent' || node.$type === 'bpmn:IntermediateThrowEvent' || node.$type === 'bpmn:BoundaryEvent';

        if (isTaskOrGateway) {
          // 用户任务节点或网关节点处理
          this.handleTaskOrGateway(node, canvas, nodeData, completeTask, todoTask);
        } else if (isStartEvent) {
          // 开始事件节点处理
          this.handleStartEvent(node, canvas, nodeData);
        } else if (isEndEvent) {
          // 结束事件节点处理
          this.handleEndEvent(node, canvas, nodeData);
        } else if (isEventNode) {
          // 事件节点处理
          this.handleEventNode(node, canvas, nodeData, completeTask);
        }
      });
    }
  }
}

</script>

<style lang="scss">
@import "../style/flow-viewer.scss";
</style>
